'''
Created on 16/gen/2010

@author: syn
'''
from elixir import session
from ui.GladeBase import GladeBase
from utils.Environment import logger, envir
from data.models import Order, Bookshop, Product, OrderDetail
from ui import get_save_dialog, check_authorization, \
    BOOKSHOP, generic_data_error
from ui.treemodels import OrderListStore, BookshopListStore, ProductListStore
import gtk
import locale

NO_ENTITY = -1

ORDER_NEW = u'new'
ORDER_PREPARING = u'preparing'
ORDER_DELIVERING = u'delivering'
ORDER_COMPLETED = u'completed'
ORDER_REJECTED = u'rejected'
ORDER_STATUS = (ORDER_NEW, ORDER_PREPARING, ORDER_DELIVERING,
                ORDER_COMPLETED, ORDER_REJECTED)

def total_amount(price, quantity, discount):
    total_amount = (quantity * price) * (1 - discount / 100)
    return total_amount
    
class ManageOrder(GladeBase):
    def __init__(self, query=Order.query, top_component=None):
        logger.debug("UI: %s instance created" % self.__class__)
        GladeBase.__init__(self, 'manage_order_frame', top_component)
        self.order_frame_hpaned.set_position(400)
        
        # Authorization setup
        bs_query = Bookshop.query
        if check_authorization(envir.get_user(), BOOKSHOP):
            query = query.filter_by(bookshop=envir.get_user().subject)
            
            bs_query = bs_query.filter_by(id=envir.get_user().subject.id)
            self.bookshop_combobox.set_sensitive(False)
            self.status_combobox.set_sensitive(False)
            
        # Setting up order list
        self.order_list = OrderListStore(Order, query.order_by('-date').all())
        self.order_treeview.set_model(self.order_list)

        # set up bookshops combobox
        bookshop_list = BookshopListStore(Bookshop, bs_query.all)
        self.bookshop_combobox.set_model(bookshop_list)
        
        # set up status combobox
        status_list = gtk.ListStore(str)
        for status in ORDER_STATUS:
            status_list.append([status])
        self.status_combobox.set_model(status_list)
        
        # set up treeview for product list
        self.product_list = ProductListStore(Product, Product.query.all)
        self.product_treeview.set_model(self.product_list)
        
        # setup treeview for order details
        self.detail_list = gtk.ListStore(str, int, float, float, float, int)
        self.detail_treeview.set_model(self.detail_list)
        
        product_tvc = gtk.TreeViewColumn('Product') 
        quantity_tvc = gtk.TreeViewColumn('Quantity')
        price_tvc = gtk.TreeViewColumn('Price')
        discount_tvc = gtk.TreeViewColumn('Discount')
        total_tvc = gtk.TreeViewColumn('Total')
        
        self.detail_treeview.append_column(product_tvc)
        self.detail_treeview.append_column(quantity_tvc)
        self.detail_treeview.append_column(price_tvc)
        self.detail_treeview.append_column(discount_tvc)
        self.detail_treeview.append_column(total_tvc)
        
        product_cell = gtk.CellRendererText()
        quantity_cell = gtk.CellRendererSpin()
        quantity_cell.set_property("editable", True)
        quantity_cell.set_property("adjustment", 
            gtk.Adjustment(upper=9999, step_incr=1, page_incr=0, page_size=0))
        price_cell = gtk.CellRendererText()
        discount_cell = gtk.CellRendererText()
        total_cell = gtk.CellRendererText()
        
        product_tvc.pack_start(product_cell, True)
        product_tvc.add_attribute(product_cell, 'text', 0)
        
        quantity_tvc.pack_start(quantity_cell, True)
        quantity_tvc.add_attribute(quantity_cell, 'text', 1)
        
        price_tvc.pack_start(price_cell, False)
        price_tvc.add_attribute(price_cell, 'text', 2)
        
        discount_tvc.pack_start(discount_cell, False)
        discount_tvc.add_attribute(discount_cell, 'text', 3)
        
        total_tvc.pack_start(total_cell, False)
        total_tvc.add_attribute(total_cell, 'text', 4)
        
        # Connecting events
        quantity_cell.connect('edited', self.on_quantity_changed)
        self.detail_list.connect('row-changed', self.on_order_changed)
        
        # Init all gui's component
        self._init_gui_components()
        
        self.entity_key = NO_ENTITY
    
    def _init_gui_components(self):
        """
        Intialize gui components as needed. This is useful in the contructor or 
        binded with particular actions (for instance, a "clear" button, or "new" button) 
        """
        self.bookshop_combobox.set_active(-1)
        if check_authorization(envir.get_user(), BOOKSHOP):
            self.bookshop_combobox.set_active(0)
        
        self.status_combobox.set_active(0)
        
        iter = self.detail_list.get_iter_first()
        while iter:
            self.detail_list.remove(iter)
            iter = self.detail_list.get_iter_first()
        
        self.total_text.set_text("")
        self.order_total = 0.0
        self.apply_button.set_sensitive(False)
        self.order_form.set_sensitive(True)

    def _retrieve_components(self):
        """
        Retrieve all used gui components from builder. This method is called in the
        GladeBase constructor
        """
        self.get_from_builder('apply_button')
        self.get_from_builder('order_treeview')
        self.get_from_builder('detail_treeview')
        self.get_from_builder('product_treeview')
        self.get_from_builder('bookshop_combobox')
        self.get_from_builder('status_combobox')
        self.get_from_builder('total_text')
        self.get_from_builder('order_form_vbox', 'order_form')
        self.get_from_builder('order_frame_hpaned')
        
    def _has_valid_data(self):
        """
        Formal control for data in the input form.
        @return: boolean. 'True' when data is valid
        """
        iter = self.bookshop_combobox.get_active_iter()
        if not iter:
            generic_data_error("Please select a bookshop", self.bookshop_combobox)
            return False
        
        iter = self.detail_list.get_iter_first()
        if not iter:
            generic_data_error("Order is empty", self.detail_treeview)
            return False
        
        return True
        
    def _save_data(self):
        """
        Save changes to db. 
        @return: 'True' if data have been successfully saved 
        """
        if not self._has_valid_data():
            return False
        
        # manage Order data object
        if self.entity_key == NO_ENTITY:
            order = Order()
        else:
            order = Order.get_by(id=self.entity_key)
        
        iter = self.bookshop_combobox.get_active_iter()
        order.bookshop = self.bookshop_combobox.get_model().get_entity(iter)
        order.status = self.status_combobox.get_active_text()
        order.total_amount = self.order_total
        
        for dt in order.detail:
            dt.delete()
            
        for (name, quantity, price, discount, total, id) in self.detail_list:
            product = Product.get_by(id=id)
            det = OrderDetail()
            det.product = product
            det.order = order
            det.quantity = quantity
            
        # save changes
        session.commit()
        
        if self.entity_key == NO_ENTITY:
            self.order_list.add(order)
            
        self.entity_key = order.id
        self.apply_button.set_sensitive(False)
        return True
    
    def _can_edit_order(self, order):
        if order.status in (ORDER_NEW, ORDER_PREPARING):
            return True
        
        return False
    
    # Signals
    def on_new_button_clicked(self, object, data=None):
        if self.apply_button.get_property('sensitive'):
            res = get_save_dialog(self.get_top_component(), "Save changes?")
            if res == gtk.RESPONSE_OK:
                if not self._save_data():
                    return
                
        self._init_gui_components()
        self.order_treeview.get_selection().unselect_all()
        self.entity_key = NO_ENTITY
    
    def on_apply_button_clicked(self, object, data=None):
        self._save_data()
    
    def on_delete_button_clicked(self, object, data=None):
        (model, iter) = self.order_treeview.get_selection().get_selected()
        if not iter:
            return
        
        entity = model.get_entity(iter)
        if not self._can_edit_order(entity):
            generic_data_error("This order is %s and can't be deleted" % entity.status,
                               self.order_treeview)
            return
            
        model.remove(iter)
        entity.delete()
        self._init_gui_components()
        self.entity_key = NO_ENTITY
        session.commit()

    def on_order_changed(self, *args, **kwargs):
        self.apply_button.set_sensitive(True)
    
    def on_order_treeview_row_activated(self, treeview, path, view_column, data=None):
        if self.apply_button.get_property('sensitive'):
            res = get_save_dialog(self.get_top_component(), "Save changes?")
            if res == gtk.RESPONSE_OK:
                if not self._save_data():
                    return
                    
        self._init_gui_components()
        
        self.entity_key = self.order_list[path][0]
        order = Order.get_by(id=self.entity_key)

        iter = self.bookshop_combobox.get_model().get_iter_by_entity(order.bookshop)
        self.bookshop_combobox.set_active_iter(iter)
        
        index = ORDER_STATUS.index(order.status)
        self.status_combobox.set_active(index)
        
        for detail in order.detail:
            detail_total = total_amount(detail.product.price, detail.quantity, detail.product.discount)
            row = [detail.product.name, detail.quantity, detail.product.price, 
                   detail.product.discount, round(detail_total, 2), detail.product.id]
            self.order_total += detail_total
            self.detail_list.append(row)
        
        self.total_text.set_text(locale.currency(self.order_total))
        
        if check_authorization(envir.get_user(), BOOKSHOP) and not self._can_edit_order(order):
            self.order_form.set_sensitive(False)
        
        self.apply_button.set_sensitive(False)

    def on_remove_button_clicked(self, object, data=None):
        (model, iter) = self.detail_treeview.get_selection().get_selected()
        if not iter:
            return
        
        self.order_total -= model.get_value(iter, 4)
        
        # Increase product quantity
        product = Product.get_by(id=model.get_value(iter, 5))
        product.quantity += model.get_value(iter, 1)
        
        model.remove(iter)
        self.total_text.set_text(locale.currency(self.order_total))
    
    def on_add_button_clicked(self, object, data=None):
        (model, iter) = self.product_treeview.get_selection().get_selected()
        if not iter:
            return
        
        product = model.get_entity(iter)
        if product.quantity == 0:
            generic_data_error("This product is unavailable at the moment",
                                self.detail_treeview)
            return
        
        # Avoid duplications
        for detail in self.detail_list:
            if product.id == detail[5]:
                return
        
        detail_total = total_amount(product.price, 1, product.discount)
        row = [product.name, 1, product.price, product.discount, 
               detail_total, product.id]
        self.detail_list.append(row)
        self.order_total += detail_total
        self.total_text.set_text(locale.currency(self.order_total))
        
        # Decrease product quantity
        product.quantity -= 1
    
    def on_quantity_changed(self, object, path, new_val, data=None):
        (name, quantity, price, discount, total, id) = self.detail_list[path]
        new_val = int(new_val)
        if new_val == quantity: 
            return
        
        diff = new_val - quantity
        product = Product.get_by(id=id)
        if new_val > quantity:
            if diff > product.quantity:
                generic_data_error("The amount chosen is not available for this item", 
                               self.detail_treeview)
                return
        
        self.order_total -= float(total)
        
        # Change product quantity
        product.quantity -= diff
        
        total = total_amount(float(price), new_val, float(discount))
        self.order_total += total
        self.total_text.set_text(locale.currency(self.order_total))
        
        self.detail_list[path] = (name, new_val, price, discount, total, id)
        
    def on_click_handle(self, paned, data=None):
        print paned.get_property('max-position')
        print paned.get_properties()
        paned.set_posistion(paned.get_property('max-position'))
        